#include <kutils.h>
#include <stdio.h>
#include "multiboot.h"
#include "display.h"
#include "keyboard.h"
#include "paging.h"
#include "memory.h"
#include "hardware_detection.h"
#include "pit.h"
#include "rtc.h"
#include "ata.h"
#include "fat.h"
#include "sound.h"
#include "idt.h"
#include "irq.h"
#include "gdt.h"
#include "apm.h"
#include "fdc.h"
#include "syscall.h"
#include "mouse.h"
#include "task.h"

s32int kmain(multiboot_info_t* mbd);
void gboot_update(u8int percent);//, s8int* message)
void one(void);
void two(void);

u32int system_mem_kb;
u8int boot_device;
u8int boot_partition;
extern fs_node_t *fs_root; // The root of the filesystem.

extern address_space_t* kspace;

s32int kmain(multiboot_info_t* mbd)
{
	init_video();
	set80x60();
	
	gboot_update(0);

#ifdef FLUIDIUM_DEBUG
	write_string("Reading information from GRUB...\n");
#endif
	if(mbd->flags & 0x01)//check that bit zero is set
	{
		system_mem_kb = mbd->mem_upper + mbd->mem_lower;
	}
	else
	{
		settextcolor(VGA_RED,VGA_BLACK);	
		write_string("Warning: Memory size information not avaliable.\nAssuming atleast 4 Megabytes of memory.\n");
		settextcolor(VGA_WHITE,VGA_BLACK);
		system_mem_kb = 0x400000;//4mb				
	}

	if(mbd->flags & 0x02)//check that bit one is set
	{
		boot_device = (u8int)(mbd->boot_device >> 24);
	}
	else
	{
		settextcolor(VGA_RED,VGA_BLACK);	
		write_string("Warning: Boot device information not avaliable. Defaulting to the floppy drive.\n");
		settextcolor(VGA_WHITE,VGA_BLACK);
		boot_device = 0;//default to floppy drive.			
	}

	if(mbd->flags & 0x4)
	{
		//we have a valid memory map
	}
	else
	{
		settextcolor(VGA_RED,VGA_BLACK);	
		write_string("Warning: Memory map not avaliable. Defaulting to a flat memory map.\n");
		settextcolor(VGA_WHITE,VGA_BLACK);
	}

	gboot_update(10);

	gdt_install();
	idt_install();
	isrs_install();//Interrupt Service Routines
	irq_install();//Interrupt Requests
	init_syscall();
	enable_interrupts();

	init_memory(system_mem_kb * 1024, mbd);
	init_mem_interface();

	gboot_update(20);

	// At this pos32int all the devices should be scanned and (re)initalized.
	hw_scan();

	gboot_update(25);

	init_vfs();
	init_vfs_interface();
	init_video_interface();	

	gboot_update(30);

	init_pit();

	gboot_update(35);

	init_rtc();
	init_rtc_interface();

	gboot_update(40);

	init_kbd();
	init_kbd_interface();
	//init_mouse();

	gboot_update(50);

	init_fdc();
	init_fdc_interface();

	gboot_update(55);

	init_ata();
	init_ata_interface();

	gboot_update(60);

	init_sound();

	beep(200, 1, 400, 10);
	beep(300, 1, 50, 10);
	beep(400, 1, 50, 10);
	beep(500, 1, 50, 10);
	beep(600, 1, 50, 10);
	beep(800, 1, 500, 10);

	gboot_update(70);

	write_string("Mounting Filesystems (root: ");
	if(boot_device & 0x80)
	{
		write_string("hard drive)...\n");

		write_string("\t/devices/disk0part0 [");
		if(!fat_mount(fs_root, (u8int*)"/devices/disk0part0"))
		{
			write_string("\nCould not mount /devices/disk0part0.\n");
		}
		
	}
	else
	{
		write_string("floppy drive)...\n");

		write_string("\t/devices/fda [");
		if(!fat_mount(fs_root, (u8int*)"/devices/fda"))
		{
			write_string("\nCould not mount /devices/fda.\n");
		}
	}
	write_string("]\n");

	gboot_update(80);

	init_apm();
	init_apm_interface();

	gboot_update(85);

//task_create("1", (u32int)one);
//task_create("2", (u32int)two);

	init_task_interface();
	init_tasking();

	gboot_update(90);
	
	//settextcolor(VGA_BLUE_LIGHT,VGA_BLACK);
	//write_string("Loading shell...\n");
	//settextcolor(VGA_WHITE,VGA_BLACK);

	disable_scroll();
	task_exec("/packages/turtle/turtle");
	//write_string("1\n");
	//task_exec("/packages/solstice/solstice");
	//write_string("2\n");

	while(1){/*write_string("2\n");*/ wait_interrupt(); }
	return 1;
}

s8int* line0 = "                                   . |                                          ";
s8int* line1 = "                                  m /                                           ";
s8int* line2 = "   [::::]                       u _/                                            ";
s8int* line3 = "   ||     ||                  i _/                                              ";
s8int* line4 = "   ||     ||    || ||  ^  [) __/                                                ";
s8int* line5 = "   |::]   ||    || ||  |  __/                                                   ";
s8int* line6 = "   ||     ||    |:::| ___/              Welcome! Please wait...                 ";
s8int* line7 = "   ||     |::]  _____/                                                          ";
s8int* line8 = "   ||    ______/                                                                ";
s8int* line9 = "________/                                                                       ";

void gboot_update(u8int percent)//, s8int* message)
{
	u8int blocks = (u8int)((percent * 75) / 100);
	u8int i = 0;

	clear_screen();
	set_pointer(0,0);
	set_cursor(0,0);

	write_string(line0);
	write_string(line1);
	write_string(line2);
	write_string(line3);
	write_string(line4);
	write_string(line5);
	write_string(line6);
	write_string(line7);
	write_string(line8);
	write_string(line9);
	write_string("\n");
	write_string(" [");
	for(i = 0; i < 75; i++)
	{
		if(i < blocks)
			write_char(':');
		else
			write_char('-');
	}
	write_string("]\n\n");
	
	write_string(" [ ");
	write_number(percent);
	write_string("% ] ");
	
}

void one(void)
{
	while(1)
	{
		write_char('1');
		__asm__ ("hlt");
	}

	task_exit();
}

void two(void)
{
	while(1)
	{
		write_char('2');
		__asm__ ("hlt");
	}
	task_exit();
}
